package org.ghost.springboot2.demo.component.datasource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.ghost.springboot2.demo.component.datasource.constant.DbContextEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * 这里设置的切入点一定要是单一的SQL操作，如DAO层、mapper层等。如果切入方法里面包含了很多方法，有读有写会导致怪事发生
 */
@Aspect
@Component
public class DbContextSwitch {
    private final static Logger logger = LoggerFactory.getLogger(DbContextSwitch.class);

    @Pointcut(
            "@annotation(org.ghost.springboot2.demo.component.datasource.annotation.Slave) " +
                    "|| execution(* org.ghost.springboot2.demo.service..*.select*(..)) " +
                    "|| execution(* org.ghost.springboot2.demo.service..*.query*(..)) " +
                    "|| execution(* org.ghost.springboot2.demo.service..*.get*(..))"
    )
    public void slave() {

    }

    @Pointcut(
            "@annotation(org.ghost.springboot2.demo.component.datasource.annotation.Master) " +
                    "|| execution(* org.ghost.springboot2.demo.service..*.insert*(..)) " +
                    "|| execution(* org.ghost.springboot2.demo.service..*.update*(..)) " +
                    "|| execution(* org.ghost.springboot2.demo.service..*.update*(..)) " +
                    "|| execution(* org.ghost.springboot2.demo.service..*.delete*(..)) "
    )
    public void master() {

    }

    /**
     * 写中有读,读也要走主库
     */
    @Before("slave()")
    public void switchToSlave() {
        if (DbContext.getDbContext() == null) {
            DbContext.switchToSlave();
            logger.info("*****DbContextSwitch切换到slave");
        }
    }

    @Before("master()")
    public void switchToMaster() {
        DbContextEnum dbContextEnum = DbContext.getDbContext();
        if (dbContextEnum == null || Objects.equals(DbContextEnum.SLAVE, dbContextEnum)) {
            DbContext.switchToMaster();
            logger.info("*****DbContextSwitch切换到master");
        }
    }

    @AfterReturning(value = "slave()", returning = "result")
    public void slaveAfterReturning(JoinPoint joinPoint, Object result) {
        if (Objects.equals(DbContextEnum.SLAVE, DbContext.getDbContext())) {
            DbContext.remove();
            logger.info("*****DbContextSwitch从slave中remove");
        }
    }

    @AfterReturning(value = "master()", returning = "result")
    public void masterAfterReturning(JoinPoint joinPoint, Object result) {
        if (Objects.equals(DbContextEnum.MASTER, DbContext.getDbContext())) {
            DbContext.remove();
            logger.info("*****DbContextSwitch从master中remove");

        }
    }

    @AfterThrowing(value = "slave()", throwing = "exception")
    public void slaveAfterThrowing(JoinPoint joinPoint, Throwable exception) {
        if (Objects.equals(DbContextEnum.SLAVE, DbContext.getDbContext())) {
            DbContext.remove();
            logger.info("*****DbContextSwitch从slave中remove");
        }
    }

    @AfterThrowing(value = "master()", throwing = "exception")
    public void masterAfterThrowing(JoinPoint joinPoint, Throwable exception) {
        if (Objects.equals(DbContextEnum.MASTER, DbContext.getDbContext())) {
            DbContext.remove();
            logger.info("*****DbContextSwitch从master中remove");
        }
    }
}
